package com.bjsxt.aspect;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSON;
import com.bjsxt.domain.SysUserLog;
import com.bjsxt.model.WebLog;
import com.bjsxt.service.SysUserLogService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

//@Component
@Aspect
@Order(2)
@Slf4j
class WebLogAdminAspect {
    /**
     * 1: 机器id
     * 2：应用id
     */
    private Snowflake snowflake = new Snowflake(1,1);

    @Autowired
    private SysUserLogService sysUserLogService;

/**
 * 日志记录
 *  环绕通知
 */

/**
 * 1 定义切入点
 */
@Pointcut("execution(* com.bjsxt.controller.*.*(..))") //controller 包里面所有类 方法 都有该切面
public  void weblog(){}


/**
 * 2 记录日志 环绕通知
 */
@Around("weblog()")
public Object recodeWebLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    Object result = null;
    WebLog webLog = new WebLog();
    Long start = System.currentTimeMillis();

    //执行方法的真实调用
    result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());

    long end = System.currentTimeMillis();

    webLog.setSpendTime((int)(start - end)/1000);
    // 获取当前请求的request对象
    ServletRequestAttributes requestAttribute = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = requestAttribute.getRequest();

    //获取安全上下文
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    String url = request.getRequestURL().toString();
    webLog.setUri(request.getRequestURI());
    webLog.setUrl(url);
    webLog.setBasePath(StrUtil.removeSuffix(url, URLUtil.url(url).getPath()));
    webLog.setUsername(authentication==null?"anonymous":authentication.getPrincipal().toString()); //获取用户Id
    webLog.setIp(request.getRemoteAddr()); //  TODO 获取使用者Ip

    //Swagger  方法上@ApiOperation（value=""）
    //获取方法
    MethodSignature signature = (MethodSignature)proceedingJoinPoint.getSignature();
    //获取类的名称
    String targetClassName = proceedingJoinPoint.getTarget().getClass().getName();
    Method method = signature.getMethod();

    //获取swagger 注解
    ApiOperation annotation = method.getAnnotation(ApiOperation.class);
    webLog.setDescription(annotation == null?"no desc": annotation.value());
    webLog.setMethod(targetClassName+"."+method.getName()); //com.bjsxt.controller.UserController.login()
    webLog.setParameter(getMethodParameter(method,proceedingJoinPoint.getArgs()));//""{"key 参数名称","value 参数的值"}
    webLog.setResult(result);

    SysUserLog sysUserLog = new SysUserLog();
    sysUserLog.setId(snowflake.nextId());
    sysUserLog.setCreated(new Date());
    sysUserLog.setDescription(webLog.getDescription());
    sysUserLog.setGroup(webLog.getDescription());
    sysUserLog.setUserId(Long.valueOf(webLog.getUsername()));
    sysUserLog.setMethod(webLog.getMethod());
    sysUserLog.setIp(webLog.getIp());
    sysUserLogService.save(sysUserLog);
    return  result;
}


    /**
     * 获取方法的执行参数
     * @param method
     * @param args
     * @return map {"key","value"}
     */
    private Object getMethodParameter(Method method, Object[] args) {
        Map<String,Object> MethodParametersWithValues = new HashMap<>();
        LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = localVariableTableParameterNameDiscoverer.getParameterNames(method);

        for (int i = 0;i<parameterNames.length;i++){
            MethodParametersWithValues.put(parameterNames[i],args[i]);
        }
        return  MethodParametersWithValues;


    }
}
